package vben.core.framework.security.authc;

import com.alibaba.fastjson.JSON;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import vben.core.common.mvc.dao.JdbcDao;
import vben.core.common.utils.lang.SecureUtils;
import vben.core.framework.ldap.LdapHandler;
import vben.core.framework.security.authz.AuthzApiData;
import vben.core.framework.security.pojo.Yapi;
import vben.core.framework.security.pojo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

//认证Service
@Service
@Transactional(rollbackFor = Exception.class)
public class AuthcService {

    public UserDo getDbUserByUsername(String username) {
        UserDo userDo = null;
        try {
            userDo = jdbcDao.getTp().queryForObject(
                    "select t.id,t.name,t.usnam,t.monum,t.pacod,t.relog,t.catag,t.tier,t.type,t.depid,'org' label,d.name depna,t.avimg from sys_org_user t " +
                            "left join sys_org_dept d on d.id=t.depid where (t.usnam=?  or t.monum=? or t.email=?) and t.avtag=1",
                    new Object[]{username,username,username}, new BeanPropertyRowMapper<>(UserDo.class));
        } catch (DataAccessException ignored) {
            try {
                userDo = jdbcDao.getTp().queryForObject(
                        "select t.id,t.name,t.usnam,t.monum,t.pacod,t.relog,t.catag,t.tier,t.type,t.corid depid,c.catid label,c.name depna,t.avimg from sys_coop_user t " +
                                "left join sys_coop_corp c on c.id=t.corid where (t.usnam=? or t.monum=? or t.email=?) and t.avtag=1",
                        new Object[]{username,username,username}, new BeanPropertyRowMapper<>(UserDo.class));
            } catch (DataAccessException ignored2) {
            }
        }
        return userDo;
    }

    public UserDo getDbUserById(String id) {
        UserDo userDo = null;
        try {
            userDo = jdbcDao.getTp().queryForObject("select t.id,t.name,t.usnam,t.monum,t.pacod,t.relog,t.catag,t.tier,t.type,t.depid,'org' label,d.name depna,t.avimg from sys_org_user t " +
                            "left join sys_org_dept d on d.id=t.depid where t.id=? and t.avtag=1",
                    new Object[]{id}, new BeanPropertyRowMapper<>(UserDo.class));
        } catch (DataAccessException ignored) {
            try {
                userDo = jdbcDao.getTp().queryForObject("select t.id,t.name,t.usnam,t.monum,t.pacod,t.relog,t.catag,t.tier,t.type,t.corid depid,c.catid label,c.name depna,t.avimg from sys_coop_user t " +
                                "left join sys_coop_corp c on c.id=t.corid where t.id=? and t.avtag=1",
                        new Object[]{id}, new BeanPropertyRowMapper<>(UserDo.class));
            } catch (DataAccessException ignored2) {
            }
        }
        return userDo;
    }

    //校验密码是否正确
    public boolean check(UserDo userDo, LoginVo loginVo) {

        boolean passFlag = false;
        if (userDo != null) {
            //前台传入的登录密码做加盐MD5加密
            String encodePassword = SecureUtils.passwordEncrypt(loginVo.getPassword());
            //比较数据里的加盐密码是否相同
            if (encodePassword.equals(userDo.getPacod())) {
                passFlag = true;
            } else {
                //如数据库校验不通过，可尝试其他方式校验，比如下面的AD域密码验证校验
                passFlag = ldapHandler.authenticate(loginVo.getUsername(), loginVo.getPassword());
            }
        }
        return passFlag;
    }

    //初始化用户
    //查询用户组织架构可用集，门户列表，菜单树，API权限集
    //查询完后做缓存，下次查询直接通过缓存查询
    public void initZuser(Zuser zuser, UserDo userDo, Map<String, Object> backMap) {
        //判断是否已经初始化过了，如已初始化，则可走缓存路线
        if (!userDo.getCatag()) {//数据库按步骤路线
            //1.获取用户所有的组织架构集:conds
            if ("org".equals(userDo.getLabel())) {
                zuser.setConds(orgHandler.findConds(userDo));
            } else {
                zuser.setConds(orgHandler.findCoopConds(userDo));
            }

            //2.根据组织架构集conds查询前台菜单集:menus
            List<Zmenu> menuList;
            List<Zportal> portalList;
            if (zuser.isAdmin()) {
                portalList = portalHandler.findAllPortalList();
                menuList = portalHandler.findSysMenuList(portalList.get(0).getId());
            } else {
                portalList = portalHandler.findPortalList(zuser.getConds());
                if (portalList != null && portalList.size() > 0) {
                    menuList = portalHandler.findMenuList(zuser.getConds(), portalList, portalList.get(0).getId());
                } else {
                    menuList = portalHandler.findNoPowerMenuList();
                }
            }

            //3.根据组织架构集conds查询前台按钮集:btns
            List<String> btnList = findBtnList(zuser);//附加功能:设置zuser的权限集

            //4.设置前台返回数据
            menuList = portalHandler.buildByRecursive(menuList);
            backMap.put("portals", portalList);
            backMap.put("menus", menuList);
            backMap.put("btns", btnList);
            backMap.put("zuser", zuser);

            //5.更新用户，序列化保存数据，使下次这些数据可直接从缓存表读取
            if ("org".equals(userDo.getLabel())) {
                updateOrgUserCache(zuser, portalList, menuList, btnList);
            }
            {
                updateCoopUserCache(zuser, portalList, menuList, btnList);
            }
            //System.out.println("通过数据库");
        } else {//缓存路线，可扩展成redis方式
            Map<String, Object> map = null;
            if ("org".equals(userDo.getLabel())) {
                String sql = "select conds,menus,btns,perms,portals from sys_org_user_cache where id=?";
                map = jdbcDao.findMap(sql, zuser.getId());
                zuser.setConds((String) map.get("conds"));
            } else {
                String sql = "select conds,menus,btns,perms,portals from sys_coop_user_cache where id=?";
                map = jdbcDao.findMap(sql, zuser.getId());
                zuser.setConds((String) map.get("conds"));
            }

            List<Zmenu> menuList = JSON.parseArray((String) map.get("menus"), Zmenu.class);
            List<Zportal> portalList = JSON.parseArray((String) map.get("portals"), Zportal.class);

            String[] btnArr = null;
            String btns = (String) map.get("btns");
            if (btns != null) {
                btnArr = btns.split(";");
            }

            String[] permStrArr = null;
            String perms = (String) map.get("perms");
            if (perms != null) {
                permStrArr = perms.split(";");
            }
            long[] permLongArr = new long[permStrArr.length];
            for (int i = 0; i < permStrArr.length; i++) {
                permLongArr[i] = Long.parseLong(permStrArr[i]);
            }
            zuser.setPermArr(permLongArr);

            backMap.put("menus", menuList);
            backMap.put("portals", portalList);
            backMap.put("btns", btnArr);
            backMap.put("zuser", zuser);
            //System.out.println("通过缓存");
        }
    }

    //切换门户，根据门户id，设置菜单
    public void switchPortal(Zuser zuser, Map<String, Object> backMap, String porid) {
        //1.根据组织架构集conds查询前台菜单集:menus
        List<Zmenu> menuList;
        List<Zportal> portalList;
        if (zuser.isAdmin()) {
            portalList = portalHandler.findAllPortalList();
            menuList = portalHandler.findSysMenuList(porid);
        } else {
            portalList = portalHandler.findPortalList(zuser.getConds());
            if (portalList != null && portalList.size() > 0) {
                menuList = portalHandler.findMenuList(zuser.getConds(), portalList, porid);
            } else {
                menuList = portalHandler.findNoPowerMenuList();
            }
        }

        //2.设置前台返回数据
        menuList = portalHandler.buildByRecursive(menuList);
        backMap.put("portals", portalList);
        backMap.put("menus", menuList);
    }

    //获取用户信息
    @Transactional(readOnly = true)
    public Zuser getUser(String username) {
        Map<String, Object> map = jdbcDao.getTp().queryForMap("select u.id,u.name from sys_org_user u where u.usnam=? and u.avtag=1", username);
        Zuser user = new Zuser();
        user.setId((String) map.get("id"));
        user.setName((String) map.get("name"));
        return user;
    }

    //获取前台按钮集合，设置用户API权限集
    private List<String> findBtnList(Zuser zuser) {
        List<String> btnList = new ArrayList<>();

        String sql = "select distinct m.id url,m.pos,m.code from sys_api_main m " +
                "inner join sys_api_role_api rm on rm.mid=m.id " +
                "inner join sys_api_role_org ru on ru.rid=rm.rid " +
                "where  m.avtag=1 and ru.oid in (" + zuser.getConds() + ") and code<>0";
        List<Yapi> apiList = jdbcDao.getTp().query(sql, new BeanPropertyRowMapper<>(Yapi.class));

        int posSum = AuthzApiData.AUTHPOS + 1;
        long[] permArr = new long[posSum];
        for (Yapi api : apiList) {
            for (int i = 0; i < posSum; i++) {
                if (i == api.getPos()) {
                    permArr[i] += api.getCode();
                }
            }
            btnList.add(api.getUrl());
        }
        zuser.setPermArr(permArr);
        return btnList;
    }

    //缓存用户门户、菜单、按钮到缓存表
    private void updateOrgUserCache(Zuser zuser, List<Zportal> portalList, List<Zmenu> menuList, List<String> btnList) {

        String menus = JSON.toJSONString(menuList);
        String portals = JSON.toJSONString(portalList);
        StringBuilder btns = new StringBuilder();
        for (String str : btnList) {
            btns.append(str).append(";");
        }

        StringBuilder perms = new StringBuilder();
        for (long perm : zuser.getPermArr()) {
            perms.append(perm).append(";");
        }

        String existSql = "select count(*) from sys_org_user_cache where id=?";
        Integer integer = jdbcDao.getTp().queryForObject(existSql, new Object[]{zuser.getId()}, Integer.class);
        if (integer > 0) {
            String sql = "update sys_org_user_cache set conds=?,menus=?,btns=?,perms=?,portals=? where id=?";
            jdbcDao.update(sql, zuser.getConds(), menus, btns.toString(), perms.toString(), portals, zuser.getId());
        } else {
            String sql = "insert into sys_org_user_cache(id,conds,menus,btns,perms,portals) VALUES(?,?,?,?,?,?)";
            jdbcDao.update(sql, zuser.getId(), zuser.getConds(), menus, btns.toString(), perms.toString(), portals);
        }
        String catagSql = "update sys_org_user set catag=1 where id=?";
        jdbcDao.update(catagSql, zuser.getId());
    }

    private void updateCoopUserCache(Zuser zuser, List<Zportal> portalList, List<Zmenu> menuList, List<String> btnList) {

        String menus = JSON.toJSONString(menuList);
        String portals = JSON.toJSONString(portalList);
        StringBuilder btns = new StringBuilder();
        for (String str : btnList) {
            btns.append(str).append(";");
        }

        StringBuilder perms = new StringBuilder();
        for (long perm : zuser.getPermArr()) {
            perms.append(perm).append(";");
        }

        String existSql = "select count(*) from sys_coop_user_cache where id=?";
        Integer integer = jdbcDao.getTp().queryForObject(existSql, new Object[]{zuser.getId()}, Integer.class);
        if (integer > 0) {
            String sql = "update sys_coop_user_cache set conds=?,menus=?,btns=?,perms=?,portals=? where id=?";
            jdbcDao.update(sql, zuser.getConds(), menus, btns.toString(), perms.toString(), portals, zuser.getId());
        } else {
            String sql = "insert into sys_coop_user_cache(id,conds,menus,btns,perms,portals) VALUES(?,?,?,?,?,?)";
            jdbcDao.update(sql, zuser.getId(), zuser.getConds(), menus, btns.toString(), perms.toString(), portals);
        }
        String catagSql = "update sys_coop_user set catag=1 where id=?";
        jdbcDao.update(catagSql, zuser.getId());
    }

    @Autowired
    private AuthcOrgHandler orgHandler;

    @Autowired
    private AuthcPortalHandler portalHandler;

    @Autowired
    private JdbcDao jdbcDao;

    @Autowired
    private LdapHandler ldapHandler;
}
